﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

using CraftDotNet.Common;

namespace CraftDotNet.Servers
{
    [Serializable]
    public class ServerProperties : ISerializable
    {
        #region Properties

        /// <summary>
        /// Allows users to use flight on your server while in Survival mode, if they have a mod that provides flight installed.
        /// With allow-flight enabled griefers will possibly be more common, because it will make their work easier. In Creative mode this has no effect.
        /// false - Flight is not allowed (players in air for at least 5 seconds will be kicked).
        /// true - Flight is allowed, and used if the player has a fly mod installed.
        /// </summary>
        public bool AllowFlight { get; set; }

        /// <summary>
        /// Allows players to travel to the Nether.
        /// false - Nether portals will not work.
        /// true - The server will allow Portals to send players to the Nether.
        /// </summary>
        public bool AllowNether { get; set; }

        /// <summary>
        /// Defines the difficulty (such as damage dealt by mobs and the way hunger and poison affects players) of the server.
        /// 0 - Peaceful
        /// 1 - Easy
        /// 2 - Normal
        /// 3 - Hard
        /// </summary>
        public Difficulties Difficulty { get; set; }

        /// <summary>
        /// Enables GameSpy4 protocol server listener. Used to get information about server.
        /// </summary>
        public bool EnableQuery { get; set; }

        /// <summary>
        /// Enables remote access to the server console.
        /// </summary>
        public bool EnableRemoteConsole { get; set; }

        /// <summary>
        /// Defines the mode of gameplay.
        /// 0 - Survival
        /// 1 - Creative
        /// 2 - Adventure (only in snapshot 12w22a, and above)
        /// </summary>
        public GameModes GameMode { get; set; }

        /// <summary>
        /// Defines whether structures (such as NPC Villages) will be generated.
        /// false - Structures will not be generated in new chunks.
        /// true - Structures will be generated in new chunks.
        /// </summary>
        public bool GenerateStructures { get; set; }

        /// <summary>
        /// The "level-name" value will be used as the world name and its folder name. You may also copy your saved game folder here, and change the name to the same as that folder's to load it instead.
        /// Characters such as ' (apostrophe) may need to be escaped by adding a backslash before them.
        /// </summary>
        public string LevelName { get; set; }

        /// <summary>
        /// Add a seed for your world, as in Singleplayer.
        /// Some examples are: minecraft, 404, 1a2b3c.
        /// </summary>
        public string LevelSeed { get; set; }

        /// <summary>
        /// Determines the type of map that is generated.
        /// DEFAULT - Standard world with hills, valleys, water, etc.
        /// FLAT - A flat world with no features, meant for building.
        /// LARGEBIOMES - Same as default but all biomes are larger.
        /// </summary>
        public LevelTypes LevelType { get; set; }

        /// <summary>
        /// The maximum height in which building is allowed. Terrain may still naturally generate above a low height limit.
        /// </summary>
        public int MaxBuildHeight { get; set; }

        /// <summary>
        /// The maximum number of players that can play on the server at the same time. Note that if more players are on the server it will use more resources. Note also, op player connections are not supposed to count against the max players, but ops currently cannot join a full server. Extremely large values for this field result in the client-side user list being broken.
        /// </summary>
        public int MaxPlayers { get; set; }

        /// <summary>
        /// This is the message that is displayed in the server list of the client, below the name.
        /// Note, motd does NOT support color codes.
        /// If the MOTD is over 59 characters, the server list will likely report a communication error.
        /// </summary>
        public string MessageOfTheDay { get; set; }

        /// <summary>
        /// Server prompts client to download texture pack upon join. Put web url link to the texture pack you want players on your server to download in this space. IMPORTANT: This link must be a direct link to the actual texture pack .zip file. Also, this does not patch clients for hd texture packs, although you can place a link for a hd texture pack and it will still download. You should find a 16x16 texture pack if you want the majority of your non-patched player to be able to use this texture pack.
        /// </summary>
        public string TexturePack { get; set; }

        /// <summary>
        /// Server checks connecting players against minecraft's account database. Only set this to false if your server is not connected to the Internet. Hackers with fake accounts can connect if this is set to false! If minecraft.net is down or inaccessible, no players will be able to connect if this is set to true. Setting this variable to off purposely is called "cracking" a server, and servers that are presently with online mode off are called "cracked" servers.
        /// true - Enabled. The server will assume it has an Internet connection and check every connecting player.
        /// false - Disabled. The server will not attempt to check connecting players.
        /// </summary>
        public bool OnlineMode { get; set; }

        /// <summary>
        /// Enable PvP on the server. Players shooting themselves with arrows will only recieve damage if PvP is enabled.
        /// Note: Indirect damage sources spawned by players (such as lava, fire, TNT and to some extent water, sand and gravel) will still deal damage to other players.
        /// true - Players will be able to kill each other.
        /// false - Players cannot kill other players (Also called PvE, for Player versus Environment).
        /// </summary>
        public bool PvP { get; set; }

        /// <summary>
        /// Sets the port for the query server (see enable-query).
        /// </summary>
        public int QueryPort { get; set; }

        /// <summary>
        /// Sets the password to remote console.
        /// </summary>
        public string RemoteConsolePassword { get; set; }

        /// <summary>
        /// Sets the port to remote console.
        /// </summary>
        public int RemoteConsolePort { get; set; }

        /// <summary>
        /// Set this if you want the server to bind to a particular IP. It is strongly recommended that you leave server-ip blank!
        /// Set to blank, or the IP you want your server to run on.
        /// </summary>
        public string ServerIP { get; set; }

        /// <summary>
        /// Changes the port the server is hosting on. This port must be forwarded if the server is going through a router.
        /// </summary>
        public int ServerPort { get; set; }

        /// <summary>
        /// Determines if Animals will be able to spawn.
        /// true - Animals spawn as normal.
        /// false - Animals will immediately vanish.
        /// Tip: if you have major lag, turn this off/set to false.
        /// </summary>
        public bool SpawnAnimals { get; set; }

        /// <summary>
        /// Determines if monsters will be spawned.
        /// true - Enabled. Monsters will appear at night and in the dark.
        /// false - Disabled. No monsters.
        /// This does nothing if difficulty = 0 (peaceful) Unless your difficulty is not set to 0, when a monster can still spawn from a Monster Spawner. Tip: if you have major lag, turn this off/set to false.
        /// </summary>
        public bool SpawnMonsters { get; set; }

        /// <summary>
        /// Determines if non-player characters (NPCs) will be spawned.
        /// true - Enabled. NPCs will spawn.
        /// false - Disabled. No NPCs.
        /// </summary>
        public bool SpawnNPCs { get; set; }

        /// <summary>
        /// Sets the amount of world data the server sends the client, measured in chunks in each direction of the player. It determines the server-side viewing distance. The "Far" viewing distance is 9 chunks, sending 441 total chunks (the amount of chunks that the server will load can be seen in the debug screen).
        /// 10 is the default/recommended. Tip: if you have major lag, reduce this value.
        /// </summary>
        public int ViewDistance { get; set; }

        /// <summary>
        /// Enables a white list on the server.
        /// With a white list enabled, users not on the white list will be unable to connect. Intended for private servers, such as those for real-life friends or strangers carefully selected via an application process, for example.
        /// Note - Ops are automatically white listed, and there is no need to add them to the whitelist.
        /// false - No white list is used.
        /// true - The file white-list.txt is used to generate the white list.
        /// </summary>
        public bool WhiteList { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Deserialization constructor.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected ServerProperties(SerializationInfo info, StreamingContext context)
        {
            AllowFlight = (bool)info.GetValue("AllowFlight", typeof(bool));
            AllowNether = (bool)info.GetValue("AllowNether", typeof(bool));
            Difficulty = (Difficulties)info.GetValue("Difficulty", typeof(Difficulties));
            EnableQuery = (bool)info.GetValue("EnableQuery", typeof(bool));
            EnableRemoteConsole = (bool)info.GetValue("EnableRemoteConsole", typeof(bool));
            GameMode = (GameModes)info.GetValue("GameMode", typeof(GameModes));
            GenerateStructures = (bool)info.GetValue("GenerateStructures", typeof(bool));
            LevelName = (string)info.GetValue("LevelName", typeof(string));
            LevelSeed = (string)info.GetValue("LevelSeed", typeof(string));
            LevelType = (LevelTypes)info.GetValue("LevelType", typeof(LevelTypes));
            MaxBuildHeight = (int)info.GetValue("MaxBuildHight", typeof(int));
            MaxPlayers = (int)info.GetValue("MaxPlayers", typeof(int));
            MessageOfTheDay = (string)info.GetValue("MessageOfTheDay", typeof(string));
            TexturePack = (string)info.GetValue("TexturePack", typeof(string));
            OnlineMode = (bool)info.GetValue("OnlineMode", typeof(bool));
            PvP = (bool)info.GetValue("PvP", typeof(bool));
            QueryPort = (int)info.GetValue("QueryPort", typeof(int));
            RemoteConsolePassword = (string)info.GetValue("RemoteConsolePassword", typeof(string));
            RemoteConsolePort = (int)info.GetValue("RemoteConsolePort", typeof(int));
            ServerIP = (string)info.GetValue("ServerIP", typeof(string));
            ServerPort = (int)info.GetValue("ServerPort", typeof(int));
            SpawnAnimals = (bool)info.GetValue("SpawnAnimals", typeof(bool));
            SpawnMonsters = (bool)info.GetValue("SpawnMonsters", typeof(bool));
            SpawnNPCs = (bool)info.GetValue("SpawnNPCs", typeof(bool));
            ViewDistance = (int)info.GetValue("ViewDistance", typeof(int));
            WhiteList = (bool)info.GetValue("WhiteList", typeof(bool));
        }

        #endregion

        #region Public Methods

        public bool SaveToFile(string filePath)
        {
            bool rtn = false;

            try
            {

            }
            catch (Exception ex)
            {

            }

            return rtn;
        }

        /// <summary>
        /// Serialization method.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("AllowFlight", AllowFlight);
            info.AddValue("AllowNether", AllowNether);
            info.AddValue("Difficulty", Difficulty);
            info.AddValue("EnableQuery", EnableQuery);
            info.AddValue("EnableRemoteConsole", EnableRemoteConsole);
            info.AddValue("GameMode", GameMode);
            info.AddValue("GenerateStructures", GenerateStructures);
            info.AddValue("LevelName", LevelName);
            info.AddValue("LevelSeed", LevelSeed);
            info.AddValue("LevelType", LevelType);
            info.AddValue("MaxBuildHeight", MaxBuildHeight);
            info.AddValue("MaxPlayers", MaxPlayers);
            info.AddValue("MessageOfTheDay", MessageOfTheDay);
            info.AddValue("TexturePack", TexturePack);
            info.AddValue("OnlineMode", OnlineMode);
            info.AddValue("PvP", PvP);
            info.AddValue("QueryPort", QueryPort);
            info.AddValue("RemoteConsolePassword", RemoteConsolePassword);
            info.AddValue("RemoteConsolePort", RemoteConsolePort);
            info.AddValue("ServerIP", ServerIP);
            info.AddValue("ServerPort", ServerPort);
            info.AddValue("SpawnAnimals", SpawnAnimals);
            info.AddValue("SpawnMonsters", SpawnMonsters);
            info.AddValue("SpawnNPCs", SpawnNPCs);
            info.AddValue("ViewDistance", ViewDistance);
            info.AddValue("WhiteList", WhiteList);
        }

        #endregion
    }

    public struct ServerTemplate
    {
        public string TemplateDirectory { get; set; }
    }

    public class ServerManager
    {
        private List<Server> mServers = new List<Server>();

        public static bool CreateServer(string name, ServerTemplate template)
        {
            bool rtn = false;

            return rtn;
        }

        public static bool LoadServer(string serverRootDirectory)
        {
            bool rtn = false;

            return rtn;
        }
    }

    public class Server
    {
        #region Internal Variables

        private bool mIsLoaded = false;

        private DirectoryInfo mRootDirectory;

        #endregion

        #region Constructors

        public Server(string rootDirectory)
        {
            mRootDirectory = new DirectoryInfo(rootDirectory);
        }

        #endregion

        #region Properties

        public bool IsLoaded
        {
            get
            {
                return mIsLoaded;
            }
        }

        public DirectoryInfo RootDirectory
        {
            get
            {
                return mRootDirectory;
            }
        }

        #endregion

        #region Public Methods

        public bool Move(string newRootDirectory)
        {
            bool rtn = false;

            mRootDirectory = new DirectoryInfo(newRootDirectory);

            return rtn;
        }

        public bool Unload()
        {
            bool rtn = false;

            return rtn;
        }

        #endregion
    }
}
